using System;
using System.Linq;
using UserManagement.Dal;
using UserManagement.DomainEntity.Exceptions;

namespace UserManagement.DomainEntity
{
    /// <summary>
    /// The contact information of user
    /// </summary>
    /// <remarks>The class hold all contact information of user</remarks>
    public class UserContact
    {
        public virtual int? Id { get; private set; }

        public virtual string Name { get; set; }

        public virtual string Address { get; set; }

        public virtual string Cell { get; set; }

        public virtual string Telephone { get; set; }

        public virtual string Email { get; set; }

        public static UserContact RegisterUser(IRepository repository, UserContact contact)
        {
            if (repository == null)
            {
                throw new ArgumentNullException("repository");
            }

            string errorMsg;
            if (!IsValidNewUserContact(repository, contact, out errorMsg))
            {
                throw new NewUserContactInvalidException(errorMsg);
            }

            contact = repository.Add(contact);
            return contact;
        }

        private static bool IsValidNewUserContact(IRepository repository, UserContact contact, out string errorMsg)
        {
            if (contact == null)
            {
                errorMsg = "Null UserContact object";
                return false;
            }

            if (string.IsNullOrEmpty(contact.Name))
            {
                errorMsg = "Null or empty name found";
                return false;
            }


            // check to see if user name already exists
            var uc = repository.FindEntities<UserContact>(con => con.Name.Trim().Equals(contact.Name.Trim(), StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
            bool result;
            if (uc != null)
            {
                errorMsg = "Contact name already exists in system";
                result = false;
            }
            else
            {
                errorMsg = string.Empty;
                result = true;
            }

            return result;
        }

        private static bool IsValidUpdatedUserContact(IRepository repository, UserContact contact, out string errorMsg)
        {
            if (contact == null)
            {
                errorMsg = "Null UserContact object";
                return false;
            }

            if (string.IsNullOrEmpty(contact.Name))
            {
                errorMsg = "Null or empty name found";
                return false;
            }


            // check to see if user name already exists
            var uc = repository.FindEntities<UserContact>(con => con.Name.Trim().Equals(contact.Name.Trim(), StringComparison.OrdinalIgnoreCase) && con.Id != contact.Id).FirstOrDefault();
            bool result;
            if (uc != null)
            {
                errorMsg = "Contact name already exists in system";
                result = false;
            }
            else
            {
                errorMsg = string.Empty;
                result = true;
            }

            return result;
        }

        public static UserContact FindByName(IRepository repository, string contactName)
        {
            if (repository == null)
            {
                throw new ArgumentNullException("repository");
            }

            if (string.IsNullOrEmpty(contactName))
            {
                throw new ArgumentNullException("contactName");
            }

            return repository.FindEntities<UserContact>(con => con.Name.Trim().Equals(contactName.Trim(), StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
        }

        public static UserContact FindById(IRepository repository, int id)
        {
            return repository.FindEntityById<UserContact>(id);
        }

        public static UserContact Update(IRepository repository, UserContact contact)
        {
            string errorMsg;
            if (!IsValidUpdatedUserContact(repository, contact, out errorMsg))
            {
                throw new UpdatedUserContactInvalidException(errorMsg);
            }

            return repository.Update(contact);
        }

        public static bool IsValidExistContact(IRepository repository, UserContact contact, out string errorMsg)
        {
            if (contact.Id == null)
            {
                errorMsg = string.Format("No valid contact id");
                return false;
            }

            var con = FindById(repository, (int)contact.Id);
            if (con == null)
            {
                errorMsg = string.Format("Cannot find contact from data source");
                return false;
            }

            // todo: make sure found contact is equal to current one
            errorMsg = string.Empty;
            return true;
        }
    }
}